home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyFMenus.p < prev    next >
Encoding:
Text File  |  1997-04-18  |  9.9 KB  |  434 lines  |  [TEXT/CWIE]

  1. unit MyFMenus;
  2.  
  3. { From Peter's PNL Libraries }
  4. { Copyright 1992 Peter N Lewis }
  5. { This source may be used for any non-commercial purposes as long as I get a mention }
  6. { in the About box and Docs of any derivative program.  It may not be used in any commercial }
  7. { application without my permission }
  8.  
  9. interface
  10.  
  11.     uses
  12.         Types,
  13.         Menus, Events, MyCallProc, MyAssertions;
  14.  
  15.     type
  16.         FMenuMenuProc = procedure(themenu,theitem:integer);
  17.         FMenuCommandProc = procedure;
  18.         
  19.     var
  20.         thefmenu, thefitem: integer;
  21.         menu_modifiers: integer;
  22.  
  23.     procedure StartupFMenus;
  24.     procedure ConfigureFMenus (default: FMenuMenuProc);
  25.  
  26.     function GetFMenu (id: integer): MenuHandle;
  27. { Call this in place of GetMenu, to read in an fmnu resource.  Use InsertMenu to add it to the menu bar }
  28.     procedure SetFCommand (command: OSType; cmdproc: FMenuCommandProc);
  29. { Call this to associate a procedure with a command OSType }
  30.     procedure SetFSetMenu (command: OSType; smproc: FMenuMenuProc);
  31. { procedure smproc(themenu,theitem:integer) }
  32. { Call this to associate a procedure for enabling/disabling the menu item }
  33.     procedure SetFBoth (command: OSType; cmdproc: FMenuCommandProc; smproc: FMenuMenuProc);
  34. { This is just a short form to set both the command and SetMenu procedures }
  35.  
  36.     function DoFMenuKey (const er: EventRecord): longint;
  37. { Calls SetFMenus and then MDEF_MenuKey }
  38.     procedure SetFMenus;
  39. { Call this before MenuKey or MenuSelect to set the enables of all the menus }
  40.     procedure SetFMenu (themenu: integer);
  41. { Call this to set the enables of all the items in themenu }
  42.     procedure DoFMenu (themenu, theitem: integer);
  43. { Call this to act on a menu selection from either MenuSelect or MenuKey }
  44.  
  45. { You probably won't need these }
  46.     procedure AddFCommand (themenu, theitem: integer; command: OSType);
  47. { Call this to associate a menu item with an OSType - normally done by GetFMenu }
  48.     procedure GetCommand (themenu, theitem: integer; var command: OSType);
  49. { Call this to figure out what command OSType is associated with a menu item - normally done via DoFMenu }
  50.     procedure DoCommand (themenu, theitem: integer; command: OSType);
  51. { Call this to execute a menu command - normally done via DoFMenu }
  52.  
  53. implementation
  54.  
  55.     uses
  56.         Resources, Script, Memory, OSUtils,
  57.         BaseGlobals,MyCallProc, MyMemory, MyStartup, MyEvents, MyMathUtils;
  58.  
  59.     const
  60.         min_menu_time = 6;
  61.  
  62. {$PUSH}
  63. {$ALIGN MAC68K}
  64.  
  65.     type
  66.         fmenuHeader = record
  67.                 visible: integer;
  68.                 count: integer;
  69.                 unknown1: integer;
  70.                 menuID: integer;
  71.                 unknown2: integer;
  72.                 unknown3: integer;
  73.                 name: Str63;
  74.             end;
  75.         fmenuHeaderPtr = ^fmenuHeader;
  76.         fmenuItem = packed record
  77.                 command: OSType;
  78.                 mark: char;
  79.                 unknown2: Byte;
  80.                 cmdKey: char;
  81.                 disabled: Byte;
  82.                 name: Str63;
  83.             end;
  84.         fmenuItemPtr = ^fmenuItem;
  85.     
  86. {$ALIGN RESET}
  87. {$POP}
  88.  
  89.     type
  90.         convertRecord = record
  91.                 menu, item: integer;
  92.                 cmd: OSType;
  93.                 cmdp: FMenuCommandProc;
  94.                 smp: FMenuMenuProc;
  95.             end;
  96.         convertArray = array[1..1000] of convertRecord;
  97.         convertPtr = ^convertArray;
  98.         convertHandle = ^convertPtr;
  99.  
  100. {$ifc do_debug}
  101.     var
  102.         startup_check: integer;
  103. {$endc}
  104.  
  105.     var
  106.         convert_count: integer;
  107.         converts: convertHandle;
  108.         DefaultMenuProc: FMenuMenuProc;
  109.  
  110.     procedure AddFCommand (themenu, theitem: integer; command: OSType);
  111.     begin
  112.         if BAND(convert_count, 7) = 0 then begin
  113.             SetHandleSize(Handle(converts), (convert_count + 8) * SizeOf(convertRecord));
  114.         end;
  115.         convert_count := convert_count + 1;
  116.         with converts^^[convert_count] do begin
  117.             menu := themenu;
  118.             item := theitem;
  119.             cmd := command;
  120.             cmdp := nil;
  121.             smp := nil;
  122.         end;
  123.     end;
  124.  
  125.     procedure NextPtr (var p: univ Ptr; sp: univ Ptr);
  126.     begin
  127.         p := Ptr(longint(sp) + sp^ + 2 - ord(odd(sp^)));
  128.     end;
  129.  
  130.     function GetFMenu (id: integer): MenuHandle;
  131.         var
  132.             h: Handle;
  133.             mh: MenuHandle;
  134.             ph: fmenuHeaderPtr;
  135.             p: fmenuItemPtr;
  136.             s: Str255;
  137.             i: integer;
  138.     begin
  139.         AssertDidStartup( startup_check );
  140.         h := GetResource('fmnu', id);
  141.         HLock(h);
  142.         ph := fmenuHeaderPtr(h^);
  143.         mh := NewMenu(ph^.menuID, ph^.name);
  144.  
  145.         NextPtr(p, @ph^.name);
  146.         for i := 1 to ph^.count do begin
  147.             if p^.name = '-' then begin
  148.                 AppendMenu(mh, '(-');
  149.             end else begin
  150.                 AddFCommand(ph^.menuID, i, p^.command);
  151.                 s := p^.name;
  152.                 if p^.mark <> chr(0) then begin
  153.                     s := concat(s, '!', p^.mark);
  154.                 end;
  155.                 if p^.cmdKey <> chr(0) then begin
  156.                     s := concat(s, '/', p^.cmdKey);
  157.                 end;
  158.                 if p^.disabled = 1 then begin
  159.                     s := concat('(', s);
  160.                 end;
  161.                 AppendMenu(mh, s);
  162.             end;
  163.             NextPtr(p, @p^.name);
  164.         end;
  165.         ReleaseResource(h);
  166.  
  167.         GetFMenu := mh;
  168.     end;
  169.  
  170.     procedure FindMenu (themenu, theitem: integer; var i: integer);
  171.     begin
  172.         i := 1;
  173.         while i <= convert_count do begin
  174.             with converts^^[i] do begin
  175.                 if (menu = themenu) and (item = theitem) then begin
  176.                     Exit(FindMenu);
  177.                 end;
  178.             end;
  179.             i := i + 1;
  180.         end;
  181.         i := -1;
  182.     end;
  183.  
  184.     procedure SetFCommand (command: OSType; cmdproc: FMenuCommandProc);
  185.         var
  186.             i: integer;
  187. {$ifc do_debug}
  188.             found_one: boolean;
  189. {$endc}
  190.     begin
  191.         AssertDidStartup( startup_check );
  192.         Assert( converts <> nil );
  193. {$ifc do_debug}
  194.         found_one := false;
  195. {$endc}
  196.         for i := 1 to convert_count do begin
  197.             with converts^^[i] do begin
  198.                 if cmd = command then begin
  199.                     cmdp := cmdproc;
  200. {$ifc do_debug}
  201.                     found_one := true;
  202. {$endc}
  203.                 end;
  204.             end;
  205.         end;
  206. {$ifc do_debug}
  207.         Assert( found_one );
  208. {$endc}
  209.     end;
  210.  
  211.     procedure SetFSetMenu (command: OSType; smproc: FMenuMenuProc);
  212.         var
  213.             i: integer;
  214. {$ifc do_debug}
  215.             found_one: boolean;
  216. {$endc}
  217.     begin
  218.         AssertDidStartup( startup_check );
  219.         Assert( converts <> nil );
  220. {$ifc do_debug}
  221.         found_one := false;
  222. {$endc}
  223.         for i := 1 to convert_count do begin
  224.             with converts^^[i] do begin
  225.                 if cmd = command then begin
  226.                     smp := smproc;
  227. {$ifc do_debug}
  228.                     found_one := true;
  229. {$endc}
  230.                 end;
  231.             end;
  232.         end;
  233. {$ifc do_debug}
  234.         Assert( found_one );
  235. {$endc}
  236.     end;
  237.  
  238.     procedure SetFBoth (command: OSType; cmdproc: FMenuCommandProc; smproc: FMenuMenuProc);
  239.         var
  240.             i: integer;
  241. {$ifc do_debug}
  242.             found_one: boolean;
  243. {$endc}
  244.     begin
  245.         AssertDidStartup( startup_check );
  246.         Assert( converts <> nil );
  247. {$ifc do_debug}
  248.         found_one := false;
  249. {$endc}
  250.         for i := 1 to convert_count do begin
  251.             with converts^^[i] do begin
  252.                 if cmd = command then begin
  253.                     cmdp := cmdproc;
  254.                     smp := smproc;
  255. {$ifc do_debug}
  256.                     found_one := true;
  257. {$endc}
  258.                 end;
  259.             end;
  260.         end;
  261. {$ifc do_debug}
  262.         Assert( found_one );
  263. {$endc}
  264.     end;
  265.  
  266.     procedure GetCommand (themenu, theitem: integer; var command: OSType);
  267.         var
  268.             i: integer;
  269.     begin
  270.         FindMenu(themenu, theitem, i);
  271.         if i = -1 then begin
  272.             command := 'xxx0';
  273.         end else begin
  274.             command := converts^^[i].cmd;
  275.         end;
  276.     end;
  277.  
  278.     procedure DoCmd (themenu, theitem: integer; cmdp: FMenuCommandProc);
  279.     begin
  280.         thefmenu := themenu;
  281.         thefitem := theitem;
  282.         if cmdp = nil then begin
  283.             DefaultMenuProc(themenu, theitem);
  284.         end else begin
  285.             cmdp;
  286.         end;
  287.     end;
  288.  
  289.     procedure DoCommand (themenu, theitem: integer; command: OSType);
  290.         var
  291.             cmdproc: FMenuCommandProc;
  292.             i: integer;
  293.     begin
  294.         cmdproc := nil;
  295.         i := 1;
  296.         while i <= convert_count do begin
  297.             with converts^^[i] do begin
  298.                 if cmd = command then begin
  299.                     cmdproc := cmdp;
  300.                     leave;
  301.                 end;
  302.             end;
  303.             i := i + 1;
  304.         end;
  305.         DoCmd(themenu, theitem, cmdproc);
  306.     end;
  307.  
  308.     procedure DoFMenu (themenu, theitem: integer);
  309.         var
  310.             i: integer;
  311.             t: longint;
  312.             tmp_hack: FMenuCommandProc;
  313.     begin
  314.         t := TickCount;
  315.         FindMenu(themenu, theitem, i);
  316.         if i = -1 then begin
  317.             DoCmd(themenu, theitem, nil);
  318.         end else begin
  319.             tmp_hack := converts^^[i].cmdp;
  320.             DoCmd(themenu, theitem, tmp_hack);
  321.         end;
  322.         if not quitNow then begin
  323.             t := TickCount - t;
  324.             if t < min_menu_time then begin
  325.                 Delay(min_menu_time - t, t);
  326.             end;
  327.             HiliteMenu(0);
  328.         end;
  329.     end;
  330.  
  331.     procedure SetFMenus;
  332.         var
  333.             i: integer;
  334.             dummy: boolean;
  335.             er: EventRecord;
  336.     begin
  337.         dummy := OSEventAvail(everyEvent, er);
  338.         menu_modifiers := er.modifiers;
  339.         for i := 1 to convert_count do begin
  340.             with converts^^[i] do begin
  341.                 if smp <> nil then begin
  342.                     smp(menu, item);
  343.                 end;
  344.             end;
  345.         end;
  346.     end;
  347.  
  348.     function DoFMenuKey (const er: EventRecord): longint;
  349.         const
  350.             kMaskVirtualKey = $0000FF00; {get virtual key from event message}
  351.             kMaskASCII1 = $00FF0000;
  352.             kMaskASCII2 = $000000FF; {get key from KeyTrans return}
  353.             kKeyUpMask = $0080;
  354.         var
  355.             h: Handle;
  356.             keyCId, keyInfo: longint;
  357.             state: UInt32;
  358.             keycode: UInt16;
  359.             lowchar, highchar: integer;
  360.             ch: Char;
  361.     begin
  362.         ch := EventChar( er );
  363.         if EventHasOptionKey( er ) or EventHasControlKey( er ) then begin
  364.             keycode := BAND(SInt32(Ord4(er.modifiers)), GoodBNOT(optionKey + controlKey)); { lose option&control }
  365.             keycode := BOR(BOR(SInt16(Ord(keycode)), kKeyUpMask), EventKeyCode( er ));
  366.             state := 0;
  367.  
  368.             keyCId := GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys);
  369.             h := GetResource('KCHR', keyCId);
  370.  
  371.             if h <> nil then begin
  372.                 HLock(h); { KeyTrans won't move memory, but lock it anyway to avoid any purging or foolishness }
  373.                 keyInfo := KeyTranslate(h^, keycode, state);
  374.                 ReleaseResource(h);
  375.                 lowchar := BAND(keyInfo, $00FF);
  376.                 highchar := BAND(BSR(keyInfo, 16), $00FF);
  377.                 if lowchar <> 0 then begin
  378.                     ch := chr(lowchar);
  379.                 end;
  380.                 if highchar <> 0 then begin
  381.                     ch := chr(highchar);
  382.                 end;
  383.             end;
  384.         end;
  385.         DoFMenuKey := MenuKey(ch);
  386.     end;
  387.  
  388.     procedure SetFMenu (themenu: integer);
  389.         var
  390.             i: integer;
  391.             dummy: boolean;
  392.             er: EventRecord;
  393.     begin
  394.         dummy := OSEventAvail(everyEvent, er);
  395.         menu_modifiers := er.modifiers;
  396.         for i := 1 to convert_count do begin
  397.             with converts^^[i] do begin
  398.                 if (themenu = menu) & (smp <> nil) then begin
  399.                     smp(menu, item);
  400.                 end;
  401.             end;
  402.         end;
  403.     end;
  404.  
  405.     function InitFMenus (var msg: integer): OSStatus;
  406.     begin
  407. {$unused(msg)}
  408.         AssertDidStartup( startup_check );
  409.         convert_count := 0;
  410.         InitFMenus := MNewHandle(converts, 0);
  411.     end;
  412.  
  413.     procedure FinishFMenus;
  414.     begin
  415.         MDisposeHandle( converts );
  416.     end;
  417.  
  418.     procedure ConfigureFMenus (default: FMenuMenuProc);
  419.     begin
  420.         DidStartup( startup_check );
  421.         StartupFMenus;
  422.         if default = nil then begin
  423.             default := DoFMenu;
  424.         end;
  425.         DefaultMenuProc := default;
  426.     end;
  427.     
  428.     procedure StartupFMenus;
  429.     begin
  430.         SetStartup(InitFMenus, nil, 0, FinishFMenus);
  431.     end;
  432.     
  433. end.
  434.